//Included

#include "program.h"



//Defined

#define PORT 4245

#define closesocket(s) shutdown(s, SHUT_RDWR)





void* f_thread_KeyListener(binder *b)
{

	sleep(rand()%3);
	//printf("je suis le thread %d %d\n",getpid(),pthread_self());
	while (1) {
		char *s = malloc (sizeof (*s) * BUFSIZ);
		char c;
		int i = 0;
		do{
			c=getchar();
			s[i] = (char)c;
			i++;
		}
		while(c!='\n');
		//Formatage de la chaine de caractere
		s[i-1]= '\0';
		handler_KeyEvents(s,b);
		sched_yield();
		
	}
	pthread_exit(NULL);
	
}
void * d_thread_serveur(binder *b){
	sleep(rand()%3);
	//printf("je suis le thread %d %d\n",getpid(),pthread_self());
	bind_serveur(b) ;
	pthread_exit(NULL);
}

//Main
int main (int argc, const char * argv[]) {
	int PORT_S = PORT;/*le port du serveur*/
	char * IP_S = "127.0.0.1";/*adresse ip serveur*/
	char *  PATH_S = malloc(BUFSIZ);
	PATH_S = ".";/*repertoire courant*/
	int csock= -1;//scoket client
	int semid;/*les semaphore responsable de la distrubition des threads*/
	SOCKET sock = -1;
	clientlist_t * listeClients;/*liste de client connecter sur le serveur*/
	ListeUpload * listeUpload;
	ListeDownload * listeDownload;
	filelist_t * listeFichiers;/*liste des fichiers disponnible dans le repertoire courant*/
	int fd[2];/*pipe de communication entre thread client et thread serveur*/
	int fd2[2];
	pthread_mutex_t clientTableAccess = PTHREAD_MUTEX_INITIALIZER;/*section critique de la table de stockage des clients*/
	pthread_mutex_t fileTableAccess = PTHREAD_MUTEX_INITIALIZER;/*section critique de la table de stockage des fichiers*/
	pthread_mutex_t uploadTableAccess = PTHREAD_MUTEX_INITIALIZER;
	pthread_mutex_t downloadTableAccess = PTHREAD_MUTEX_INITIALIZER;
	pthread_mutex_t clientSocketAccess[FDMAX];
	pthread_mutex_t socketAccess = PTHREAD_MUTEX_INITIALIZER;
	pthread_mutex_t neighbourCondMutex = PTHREAD_MUTEX_INITIALIZER ;
	pthread_cond_t neighbourhoodCond = PTHREAD_COND_INITIALIZER ;
	int neighbourhoodbool = FAUX;
	pthread_mutex_t  listCondMutex = PTHREAD_MUTEX_INITIALIZER;
	pthread_cond_t  listCond = PTHREAD_COND_INITIALIZER;
	int   listbool = FAUX;
	pthread_mutex_t  trafficCondMutex = PTHREAD_MUTEX_INITIALIZER;
	pthread_cond_t  trafficCond = PTHREAD_COND_INITIALIZER;
	int   trafficbool = FAUX;
	int cmp;
	for (cmp = 0;cmp<FDMAX;cmp++){
		pthread_mutex_init(&clientSocketAccess[cmp],NULL);
	}
	key_t clef;
	if (argc == 0) {
		clef = ftok("key",PORT);
	}
	else {
		clef = ftok(argv[0],PORT);
	}

	srand(getpid());
	semid =semget(clef,1, IPC_CREAT| 0666);
	if(semid==-1){
		perror("semget");
		exit(EXIT_FAILURE);
	}
	/*initialisation de la semaphore */
	if((semctl(semid, 0, SETVAL,NBTHREAD)==-1)){
		perror("semctl");
	}
	if (pipe(fd)==-1) {
		perror("PIPE");
		exit(EXIT_FAILURE);
	}
	if (pipe(fd2)==-1) {
		perror("PIPE");
		exit(EXIT_FAILURE);
	}
	pthread_mutex_lock(&downloadTableAccess);
	listeDownload=malloc(sizeof(ListeDownload));
	init_listeDownload(listeDownload);
	pthread_mutex_unlock(&downloadTableAccess);
	
	pthread_t ecouteur;/*L'ecouteur du clavier*/
	pthread_t serveur;
	pthread_t th_client;
	int pid1 ;
	binder * b = malloc(sizeof(binder));
	b->sock = &sock;
	b->socketAccess = &socketAccess;
	b->ip = &IP_S;
	b->port = &PORT_S;
	b->semid = semid;
	b->listeClients = &listeClients;
	b->listeFichiers = &listeFichiers;
	b->fdpipe0 = fd[0];
	b->fdpipe1 = fd[1];
	b->fdpipes0 = fd2[0];
	b->fdpipes1 = fd2[1];
	b->path = &PATH_S;
	b->listeUpload = &listeUpload;
	b->listeDownload = &listeDownload;
	b->uploadTableAccess = &uploadTableAccess;
	b->downloadTableAccess = &downloadTableAccess;
	b->fileTableAccess = &fileTableAccess;
	b->clientTableAccess = &clientTableAccess;
	b->clientSocketAccess = clientSocketAccess;
	b->csock = &csock;
	b->neighbourhoodCond = &neighbourhoodCond;
	b->neighbourhoodCondMutex = &neighbourCondMutex;
	b->neighbourhoodbool = &neighbourhoodbool;

	b->listCond = &listCond;
	b->listCondMutex = &listCondMutex;
	b->listbool = &listbool;

	b->trafficCond = &trafficCond;
	b->trafficCondMutex = &trafficCondMutex;
	b->trafficbool = &trafficbool;
	//printf("je suis le thread principale %d %d\n",getpid(),pthread_self());
	if((pid1 = pthread_create(&ecouteur, NULL,(void*)f_thread_KeyListener,b))==-1)
		printf("probleme pthread_create \n");

	if((pid1 = pthread_create(&serveur, NULL,(void *)d_thread_serveur,b))==-1)
		printf("probleme pthread_create \n");

	if((pid1 = pthread_create(&th_client, NULL,(void*)f_thread_receiver,b))==-1)
		printf("probleme pthread_create \n");
	changer_ordo_priorite(ecouteur, SCHED_FIFO, 3);
	changer_ordo_priorite(serveur, SCHED_RR,5);
	changer_ordo_priorite(th_client, SCHED_RR,5);
	/*Attendre que les requetes se termine*/ 
	pthread_join(ecouteur,NULL);
	pthread_join(serveur,NULL);
	/*Destruction des semapohores*/
	semctl(semid, 0, IPC_RMID, 0);
	return 0;
}
